var Lexer = function (rules, skip_ws) {
    this.rules = rules;
    var regex_parts = [];
    for (var i = 0; i < rules.length; ++i) {
        regex_parts.push('(' + rules[i].pattern + ')');
    }
    this.regex = new RegExp(regex_parts.join('|'), 'g');
    this.skip_ws = skip_ws ? new RegExp('\\S', 'g') : null;
    this.buf = '';
}

// Initialize the Lexer's buffer. This resets the lexer's internal state and
// subsequent tokens will be returned starting with the beginning of the new
// buffer.
Lexer.prototype.input = function (buf) {
    this.buf = buf;
    this.regex.lastIndex = 0;
}

// Get the next token from the current buffer. A token is an object with
// the following properties:
// - name: name of the pattern that this token matched (taken from rules).
// - value: actual string value of the token.
// - pos: offset in the current buffer where the token starts.
//
// If there are no more tokens in the buffer, returns null.
// In case of an error, throws Error.
Lexer.prototype.token = function () {
    // End of input?
    if (this.regex.lastIndex >= this.buf.length) {
        return null;
    }

    if (this.skip_ws) {
        
        this.skip_ws.lastIndex = this.regex.lastIndex;
        var match = this.skip_ws.exec(this.buf);
        if (match) {
            this.regex.lastIndex = match.index;
        } else {
            return null;
        }
    }

    var result = this.regex.exec(this.buf);
    if (result === null) {
        throw Error('Cannot match a token at position ' + this.regex.lastIndex);
    } else {
        
        for (var i = 0; i < this.rules.length; i++) {
            // Find the matching rulea SO question
            if (result[i + 1] !== undefined) {
                return {
                    name: this.rules[i].name,
                    value: result[0],
                    pos: result.index
                };
            }
        }
        // Shouldn't get here, because at least one rule matched.
        throw Error('Internal error');
    }
}

/*
var rules = [{
    pattern: 'd+',
    name: 'NUMBER'
}, {
    pattern: '[a-zA-Z_]\w*',
    name: 'IDENTIFIER'
}, {
    pattern: '\\+',
    name: 'PLUS'
}, {
    pattern: '\\-',
    name: 'MINUS'
}, {
    pattern: '\\*',
    name: 'MULTIPLY'
}, {
    pattern: '\\/',
    name: 'DIVIDE'
}, {
    pattern: '\\(',
    name: 'LP'
}, {
    pattern: '\\)',
    name: 'RP'
}, {
    pattern: '\\=',
    name: 'EQUALS'
}, ]

lx =new Lexer(rules, true)
lx.input('erw = _abc + 12*(R4-623902)  ')
var r = null;
while (r = lx.token()) {
    console.log(r)
}*/